#include "minet_socket.h"
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <regex.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>

#define BUFSIZE 1024

/* MAIN */
int main(int argc, char * argv[]) {

    char * server_name = NULL;
    int server_port    = -1;
    char * server_path = NULL;
    char * req         = NULL;
    bool ok            = false;
    int sk			   = -1;
    struct hostent *host;
    struct in_addr *host_ip;
    struct sockaddr_in *host_addr;
    fd_set readfds;
    struct timeval *timeout;
    char resp_bit[2];
    char resp_header[1024];
    char resp_code[1024];
    char *resp_len_str = NULL;
    int resp_len = 0;
    int body_len = 0;
    int read = 0;
    char *resp_body = NULL;


    /*parse args */
    if (argc != 5) {
		fprintf(stderr, "usage: http_client k|u server port path\n");
		exit(-1);
    }

    server_name = argv[2];
    server_port = atoi(argv[3]);
    server_path = argv[4];

    req = (char *)malloc(strlen("GET  HTTP/1.0\r\n\r\n") + strlen(server_path) + 1);  

    /* initialize */
    if (toupper(*(argv[1])) == 'K') { 
		minet_init(MINET_KERNEL);
    } else if (toupper(*(argv[1])) == 'U') { 
		minet_init(MINET_USER);
    } else {
		fprintf(stderr, "First argument must be k or u\n");
		exit(-1);
    }

    /* make socket */
	sk = minet_socket(SOCK_STREAM);

    /* get host IP address  */
    /* Hint: use gethostbyname() */
    host = gethostbyname(server_name);
    if(!host){
        printf("ERROR: host not found.\n");
        exit(0);
    }
    host_ip = (struct in_addr*)host->h_addr;

    /* set address */
    host_addr = (sockaddr_in*)malloc(sizeof(sockaddr_in));
    host_addr->sin_family = AF_INET;
    host_addr->sin_port = htons(server_port);
    host_addr->sin_addr = *host_ip;

    /* connect to the server socket */
	if(minet_connect(sk, host_addr)) {
        printf("ERROR: failed to connect to host.\n");
        exit(0);
    }

    /* send request message */
    sprintf(req, "GET %s HTTP/1.0\r\n\r\n", server_path);
	if(minet_write(sk, req, strlen(req)) == 0) {
		printf("ERROR: failed to write request to socket.\n");
		exit(0);
	}

    /* wait till socket can be read. */
    /* Hint: use select(), and ignore timeout for now. */
    FD_ZERO(&readfds);
    FD_SET(sk, &readfds);
    timeout = (struct timeval*)malloc(sizeof(struct timeval));
    timeout->tv_sec = 10;
    minet_select(sk+1, &readfds, NULL, NULL, timeout);
    if(!FD_ISSET(sk, &readfds)){
        printf("Timed out\n");
    }

    /* first read loop -- read headers */
    resp_bit[1] = '\0';
    while(minet_read(sk, resp_bit, 1)) {
        if(!strcmp(resp_bit, "\r")){
            minet_read(sk, resp_bit, 1);
            if(!strcmp(resp_bit, "\n")){
                minet_read(sk, resp_bit, 1);
                if(!strcmp(resp_bit, "\r")){
                    minet_read(sk, resp_bit, 1);
                    if(!strcmp(resp_bit, "\n")){
                        resp_header[resp_len] = '\0';
                        break;
                    }
                }else{
                    resp_header[resp_len] = '\n';
                    resp_header[resp_len+1] = resp_bit[0];
                    resp_len = resp_len + 2;
                    continue;
                }
            }
        }else{
            resp_header[resp_len] = resp_bit[0];
            resp_len++;
        }
    }


    /* examine return code */   

    //Skip "HTTP/1.0"
    memmove(resp_code, resp_header+9, strlen(resp_header));

    // Normal reply has return code 200
    if(!strncmp(resp_code, "200 OK", 6)){
        ok = true; 
    }else{
        fprintf(stderr, "%s\n", resp_header);
        //exit(-1);
    }

    read = 0;
    body_len = 0;
    resp_body = (char*)malloc(1024);
    while((read = minet_read(sk, resp_body+body_len, 1024)) > 0){
        body_len = body_len + read;
        resp_body = (char*)realloc(resp_body, body_len+1024);
        //realloc(resp_body, body_len+1024);
    }
    
    
    /* close socket and deinitialize */
	minet_close(sk);
    minet_deinit();


    /* free malloc'ed data */
    free(req);
    free(host_addr);
    free(timeout);
    free(resp_len_str);

    if (ok) {
        //printf("%s\n", resp_body);
		printf("%s", resp_body);
        free(resp_body);
        return 0;
    } else {
        //fprintf(stderr, "\n%s\n", resp_body);
		fprintf(stderr, "\n%s", resp_body);
        free(resp_body);
        return -1;
    }
}
